package com.smartcampusbackend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smartcampusbackend.mapper.AcademicWarningMapper;
import com.smartcampusbackend.mapper.CourseMapper;
import com.smartcampusbackend.mapper.GradeMapper;
import com.smartcampusbackend.mapper.MakeupExamApplicationMapper;
import com.smartcampusbackend.model.AcademicWarning;
import com.smartcampusbackend.model.Course;
import com.smartcampusbackend.model.Grade;
import com.smartcampusbackend.model.MakeupExamApplication;
import com.smartcampusbackend.service.AcademicWarningService;
import com.smartcampusbackend.service.MakeupExamApplicationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class MakeupExamApplicationServiceImpl extends ServiceImpl<MakeupExamApplicationMapper, MakeupExamApplication> implements MakeupExamApplicationService {

    private static final Logger logger = LoggerFactory.getLogger(MakeupExamApplicationServiceImpl.class);

    @Autowired
    private MakeupExamApplicationMapper makeupExamApplicationMapper;

    @Autowired
    private AcademicWarningMapper academicWarningMapper;

    @Autowired
    private GradeMapper gradeMapper;

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private AcademicWarningService academicWarningService;

    @Override
    public boolean applyMakeupExam(MakeupExamApplication application) {
        if (application.getApplyTime() == null) {
            application.setApplyTime(LocalDateTime.now());
        }
        application.setStatus("待审核");
        
        try {
            // 手动日志记录所有字段值以方便调试
            logger.info("创建补考申请: studentId={}, courseId={}, status={}, applyTime={}", 
                    application.getStudentId(), application.getCourseId(), 
                    application.getStatus(), application.getApplyTime());
            
            // 手动检查必要字段是否非空
            if (application.getStudentId() == null || application.getStudentId().trim().isEmpty()) {
                logger.error("补考申请失败: 学生ID为空");
                return false;
            }
            if (application.getCourseId() == null || application.getCourseId().trim().isEmpty()) {
                logger.error("补考申请失败: 课程ID为空");
                return false;
            }
            
            return save(application);
        } catch (Exception e) {
            logger.error("创建补考申请失败", e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean approveApplication(Long applicationId) {
        MakeupExamApplication application = getById(applicationId);
        if (application == null) {
            return false;
        }

        application.setStatus("已批准");
        application.setReviewTime(LocalDateTime.now());

        // 更新对应的学业预警状态
        updateAcademicWarningStatus(application.getStudentId(), application.getCourseId(), "批准补考");

        return updateById(application);
    }

    @Override
    @Transactional
    public boolean reviewApplication(Long applicationId, Double makeupScore, String remark) {
        MakeupExamApplication application = getById(applicationId);
        if (application == null) {
            return false;
        }

        application.setMakeupScore(makeupScore);
        application.setRemark(remark);
        application.setReviewTime(LocalDateTime.now());

        // 判断补考成绩是否合格
        boolean isPassed = makeupScore >= 60.0;
        application.setStatus(isPassed ? "补考通过" : "补考未通过");

        // 更新对应的学业预警状态
        updateAcademicWarningStatus(application.getStudentId(), application.getCourseId(), 
                                   isPassed ? "补考通过" : "补考未通过");

        // 创建补考成绩记录
        createMakeupGradeRecord(application, isPassed);
        
        // 如果补考通过，更新学生成绩统计信息
        if (isPassed) {
            try {
                // 获取课程信息以获取学分
                Course course = courseMapper.selectById(application.getCourseId());
                if (course != null) {
                    logger.info("补考通过，更新学生成绩统计信息: studentId={}, courseId={}, courseName={}, credits={}", 
                               application.getStudentId(), application.getCourseId(), 
                               course.getName(), course.getCredits());
                    
                    // 更新学生成绩统计信息
                    gradeMapper.updateStudentGradeStatistics(application.getStudentId());
                    
                    // 同时触发学业预警检查
                    academicWarningService.generateWarningsFromGrades();
                    
                    logger.info("成功更新学生成绩统计信息");
                } else {
                    logger.warn("未找到课程信息，无法更新学分统计: courseId={}", application.getCourseId());
                }
            } catch (Exception e) {
                logger.error("更新学生成绩统计信息失败", e);
                // 继续执行，不影响补考成绩录入
            }
        }

        return updateById(application);
    }

    private void createMakeupGradeRecord(MakeupExamApplication application, boolean isPassed) {
        logger.info("开始创建补考成绩记录: studentId={}, courseId={}, score={}", 
                   application.getStudentId(), application.getCourseId(), application.getMakeupScore());
        try {
            // 查找原始成绩记录
            QueryWrapper<Grade> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("student_id", application.getStudentId())
                       .eq("course_id", application.getCourseId())
                       .not(true, q -> q.like("semester", "%补考%")); // 排除已有的补考记录
            Grade originalGrade = gradeMapper.selectOne(queryWrapper);
            if (originalGrade == null) {
                logger.warn("未找到原始成绩记录，禁止插入补考成绩: studentId={}, courseId={}", 
                           application.getStudentId(), application.getCourseId());
                return;
            }
            
            // 查找是否已有补考记录，如果有则更新，没有则插入
            QueryWrapper<Grade> makeupQuery = new QueryWrapper<>();
            makeupQuery.eq("student_id", application.getStudentId())
                      .eq("course_id", application.getCourseId())
                      .like("semester", "%补考%");
            Grade existingMakeupGrade = gradeMapper.selectOne(makeupQuery);
            
            Grade makeupGrade;
            if (existingMakeupGrade != null) {
                // 更新现有补考记录
                makeupGrade = existingMakeupGrade;
                makeupGrade.setFinalGrade(application.getMakeupScore());
                makeupGrade.setUpdateTime(LocalDateTime.now());
                makeupGrade.setRegularGrade(application.getMakeupScore());
                makeupGrade.setExamGrade(application.getMakeupScore());
                
                gradeMapper.updateById(makeupGrade);
                logger.info("更新补考成绩记录成功: studentId={}, courseId={}, score={}, isPassed={}", 
                           application.getStudentId(), application.getCourseId(), application.getMakeupScore(), isPassed);
            } else {
                // 创建新的补考记录
                makeupGrade = new Grade();
                makeupGrade.setStudentId(application.getStudentId());
                makeupGrade.setCourseId(application.getCourseId());
                makeupGrade.setSemester(originalGrade.getSemester() + "-补考");
                makeupGrade.setFinalGrade(application.getMakeupScore());
                makeupGrade.setCreateTime(LocalDateTime.now());
                makeupGrade.setUpdateTime(LocalDateTime.now());
                makeupGrade.setRegularGrade(application.getMakeupScore());
                makeupGrade.setExamGrade(application.getMakeupScore());
                
                gradeMapper.insert(makeupGrade);
                logger.info("插入补考成绩记录成功: studentId={}, courseId={}, score={}, isPassed={}", 
                           application.getStudentId(), application.getCourseId(), application.getMakeupScore(), isPassed);
            }
            
            // 更新成绩统计信息
            try {
                gradeMapper.updateStudentGradeStatistics(application.getStudentId());
                logger.info("更新学生成绩统计信息成功");
            } catch (Exception e) {
                logger.error("更新学生成绩统计信息失败", e);
            }
        } catch (Exception e) {
            logger.error("创建补考成绩记录失败", e);
        }
    }

    private void updateAcademicWarningStatus(String studentId, String courseId, String status) {
        QueryWrapper<AcademicWarning> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("student_id", studentId)
                   .eq("course_id", courseId);
        
        AcademicWarning academicWarning = academicWarningMapper.selectOne(queryWrapper);
        if (academicWarning != null) {
            // Map makeup exam status to academic warning status
            String warningStatus;
            switch (status) {
                case "待审核":
                    warningStatus = "申请补考";
                    academicWarning.setStatus("ACTIVE");
                    break;
                case "已批准":
                    warningStatus = "批准补考";
                    academicWarning.setStatus("ACTIVE");
                    break;
                case "补考通过":
                    warningStatus = "补考通过";
                    academicWarning.setStatus("RESOLVED");
                    break;
                case "补考未通过":
                    warningStatus = "补考未通过";
                    academicWarning.setStatus("ACTIVE");
                    break;
                default:
                    warningStatus = status;
                    // 默认保持原状态
                    break;
            }
            
            // 更新预警类型字段以跟踪补考状态
            if (academicWarning.getWarningType() != null && academicWarning.getWarningType().startsWith("成绩不及格")) {
                academicWarning.setWarningType("成绩不及格-" + warningStatus);
            } else {
                academicWarning.setWarningType("成绩不及格-" + warningStatus);
            }
            academicWarning.setUpdateTime(LocalDateTime.now());
            academicWarningMapper.updateById(academicWarning);
            
            logger.info("更新学业预警状态成功: studentId={}, courseId={}, status={}, warningStatus={}, 预警状态={}", 
                       studentId, courseId, status, warningStatus, academicWarning.getStatus());
        } else {
            logger.warn("未找到学业预警记录无法更新状态: studentId={}, courseId={}", 
                       studentId, courseId);
        }
    }

    @Override
    public List<MakeupExamApplication> getStudentApplications(String studentId) {
        return makeupExamApplicationMapper.findByStudentId(studentId);
    }

    @Override
    public List<MakeupExamApplication> getTeacherApplications(String teacherId) {
        return makeupExamApplicationMapper.findByTeacherId(teacherId);
    }

    @Override
    public List<MakeupExamApplication> getAllApplications() {
        return list();
    }

    @Override
    public MakeupExamApplication getApplicationById(Long id) {
        return getById(id);
    }

    @Override
    public Map<String, Object> getMakeupExamStatistics() {
        Map<String, Object> statistics = new HashMap<>();

        // 总申请数
        statistics.put("totalApplications", count());

        // 待审核数
        QueryWrapper<MakeupExamApplication> pendingQuery = new QueryWrapper<>();
        pendingQuery.eq("status", "待审核");
        statistics.put("pendingApplications", count(pendingQuery));

        // 已批准数
        QueryWrapper<MakeupExamApplication> approvedQuery = new QueryWrapper<>();
        approvedQuery.eq("status", "已批准");
        statistics.put("approvedApplications", count(approvedQuery));

        // 补考通过数
        QueryWrapper<MakeupExamApplication> passedQuery = new QueryWrapper<>();
        passedQuery.eq("status", "补考通过");
        statistics.put("passedApplications", count(passedQuery));

        // 补考未通过数
        QueryWrapper<MakeupExamApplication> failedQuery = new QueryWrapper<>();
        failedQuery.eq("status", "补考未通过");
        statistics.put("failedApplications", count(failedQuery));

        return statistics;
    }
} 